package cacheV2

import (
	"reflect"
	"strings"
	"sync"
	"sync/atomic"
	"time"
	"unsafe"
	"xxgame.com/CommApp/Util/goroutine"
	"xxgame.com/CommApp/Util/log"
	"xxgame.com/CommApp/Util/timer"
)

var initOnceMgrSub sync.Once
var initOnceMgrCtn sync.Once
var gPstSubObjMgr *ObjectCacheMgr	// PstEntity 对象管理器
var gPstCtnObjMgr *ObjectCacheMgr	// PstEntityCnt 对象管理器

var OBJ_CACHE_TIME = 3 * time.Minute

// 获取子项对象管理器
func MgrSub() *ObjectCacheMgr {
	initOnceMgrSub.Do(func() {
		gPstSubObjMgr = new(ObjectCacheMgr)
		gPstSubObjMgr.objMgrPool = &sync.Pool{
			New: func() interface{} {
				atomic.AddInt32(&gPstSubObjMgr.poolNewCnt, 1)
				return new(ObjectTagMapSt)
			},
		}
	})
	return gPstSubObjMgr
}

// 获取容器对象管理器
func MgrCtn() *ObjectCacheMgr {
	initOnceMgrCtn.Do(func() {
		gPstCtnObjMgr = new(ObjectCacheMgr)
		gPstCtnObjMgr.objMgrPool = &sync.Pool{
			New: func() interface{} {
				atomic.AddInt32(&gPstCtnObjMgr.poolNewCnt, 1)
				return new(ObjectTagMapSt)
			},
		}
	})
	return gPstCtnObjMgr
}

type ObjectCacheMgr struct {
	objCacheMap sync.Map	// map[uid] ===>>> *ObjectTagMapSt
	objMgrPool *sync.Pool	// mgr的对象池子
	poolNewCnt	int32		// 调用New次数统计
}

type ObjectTagMapSt struct {
	Count uint32			// 记录 ObjectTagMap 元素个数
	ObjectTagMap sync.Map	// map[objectTag] ===>>> *object
}

func (this *ObjectCacheMgr) Get(curGoid int64, objectTag string) interface{} {
	tagList := strings.Split(objectTag, "_")
	uidStr := tagList[1] // 获取UID
	
	objectMap_if, ok := this.objCacheMap.Load(uidStr)
	if ok {
		object, ok2 := objectMap_if.(*ObjectTagMapSt).ObjectTagMap.Load(objectTag)
		if ok2 {
			log.PST.Infof("对象管理器ObjectCacheMgr.Get()，缓存命中，返回缓存: "+
				"curGoid=%+v, objectTag=%+v", curGoid, objectTag)
			return object
		} else {
			log.PST.Debugf("对象管理器ObjectCacheMgr.Get()，无命中缓存："+
				"curGoid=%+v, objectTag=%+v", curGoid, objectTag)
		}
	}
	return nil
}

func (this *ObjectCacheMgr) GetFuzzyMatch(curGoid int64, obj interface{}, tblName string, objectTag string) interface{} {
	tagList1 := strings.Split(objectTag, "_")
	uidStr := tagList1[1] // 获取UID

	tagList := strings.Split(objectTag, "_")
	tagList = tagList[0:2]
	tagList = append(tagList, tblName)
	objectTagBase := strings.Join(tagList, "_") // 获取对象tag的根部分，如： SUB_UID_TBLName

	objectMap_if, ok := this.objCacheMap.Load(uidStr)
	if ok {
		var object interface{} = nil
		objectMap := objectMap_if.(*ObjectTagMapSt)
		objectMap.ObjectTagMap.Range(func(mapTag, object_t interface{}) bool {
			if mapTag.(string) != objectTag {
				if strings.Contains(mapTag.(string), objectTagBase) {
					// 这里遍历比较object，并且CompareEntity函数中用了大量反射，todo：性能有优化空间
					if CompareEntity(object_t, obj) {
						log.PST.Infof("对象管理器ObjectCacheMgr.GetFuzzyMatch()，缓存命中，返回缓存："+
							"curGoid=%+v, mapTag=%+v, objectTag=%+v, objectTagBase=%+v",
							curGoid, mapTag, objectTag, objectTagBase)
						object = object_t
						return false // 返回false中止遍历
					}
				}
			}
			return true  // 返回true继续遍历
		})
		return object
	}
	return nil
}

// 指定协程添加tag指定的pst对象
func (this *ObjectCacheMgr) Add(curGoid int64, object interface{}, objectTag string) bool {
	tagList1 := strings.Split(objectTag, "_")
	uidStr := tagList1[1] // 获取UID

	tagMap := this.objMgrPool.Get().(*ObjectTagMapSt)
	objectMap_if, ok := this.objCacheMap.LoadOrStore(uidStr, tagMap)
	if ok {
		this.objMgrPool.Put(tagMap)
	}
	objectMap := objectMap_if.(*ObjectTagMapSt)
	_, ok2 := objectMap.ObjectTagMap.LoadOrStore(objectTag, object)
	if !ok2 {
		atomic.AddUint32(&objectMap.Count, 1)
		log.PST.Debugf("对象管理器ObjectCacheMgr.Add()，加入缓存成功: "+
			"curGoid=%+v, objectTag=%+v", curGoid, objectTag)
		return true
	} else {
		log.PST.Errorf("对象管理器ObjectCacheMgr.Add()，对象已存在:" +
			"curGoid=%+v, objectTag=%+v", curGoid, objectTag)
	}
	return false
}

// 指定协程异常tag指定的pst对象（延迟删除）
func (this *ObjectCacheMgr) Remove(curGoid int64, objectTag string) bool {
	tagList1 := strings.Split(objectTag, "_")
	uidStr := tagList1[1] // 获取UID
	objectMap_if, ok := this.objCacheMap.Load(uidStr)
	if ok {
		objectMap := objectMap_if.(*ObjectTagMapSt)
		_, ok2 := objectMap.ObjectTagMap.Load(objectTag)
		if ok2 {
			timer.Mgr().ReStart(objectTag+"_CacheRemove", OBJ_CACHE_TIME, 1, func() {
				this.RemoveImmediately(curGoid, objectTag)
			})
		}
	}
}

// 指定协程异常tag指定的pst对象（直接删除）
func (this *ObjectCacheMgr) RemoveImmediately(curGoid int64, objectTag string) bool {
	tagList1 := strings.Split(objectTag, "_")
	uidStr := tagList1[1] // 获取UID

	objectMap_if, ok := this.objCacheMap.Load(uidStr)
	if ok {
		objectMap := objectMap_if.(*ObjectTagMapSt)
		_, ok = objectMap.ObjectTagMap.LoadAndDelete(objectTag)
		if ok {
			log.PST.Debugf("对象管理器ObjectCacheMgr.Remove()，" +
				"协程curGoid=%+v，清理标签%+v的对象", curGoid, objectTag)
			if 0 >= atomic.AddUint32(&objectMap.Count, -1) {
				log.PST.Debugf("对象管理器ObjectCacheMgr.Remove()，" +
					"协程curGoid=%+v的对象已清空", curGoid)
				// 循环五次检查是否元素个数为0，防止并发将存在元素的 objectMap 删除
				MAX_CHK_CNT := 5
				for i := 0; i < MAX_CHK_CNT; i++ {
					if 0 >= atomic.LoadUint32(&objectMap.Count) {
						if i == MAX_CHK_CNT - 1 { // 最后一次还符合条件则执行删除
							objectMap_if2, ok2 := this.objCacheMap.LoadAndDelete(uidStr)
							if ok2 {
								this.objMgrPool.Put(objectMap_if2)
								log.PST.Infof("对象管理器ObjectCacheMgr.Remove()，"+
									"协程curGoid=%+v, 清空用户 uid=%+v 所有缓存", curGoid, uidStr)
							} else {
								log.PST.Errorf("对象管理器ObjectCacheMgr.Remove()，"+
									"协程curGoid=%+v, 清空用户 uid=%+v 所有缓存失败：对象不存在！",
									curGoid, uidStr)
							}
						}
					} else {
						log.PST.Errorf("对象管理器ObjectCacheMgr.Remove()，"+
							"协程curGoid=%+v, 清空用户 uid=%+v 所有缓存失败：其他协程尝试使用！",
							curGoid, uidStr)
						break
					}
				}
			}
			return true
		} else {
			if -1 == strings.Index(objectTag, "CTN") { // 容器对象不做缓存，故过滤打印（todo：临时写法，待优化）
				log.PST.Errorf("对象管理器ObjectCacheMgr.Remove()，对象已不存在:" +
										"curGoid=%+v, objectTag=%+v", curGoid, objectTag)
			}
		}
	} else {
		log.PST.Errorf("对象管理器ObjectCacheMgr.Remove()，用户缓存对象已不存在:" +
					"curGoid=%+v, objectTag=%+v, uid=%+v", curGoid, objectTag, uidStr)
	}
	return false
}

// 判断是否同一个数据记录
// 	备注：
//		object1和object2都已从DB加载数据回来的对象（并非空对象）
func CompareEntity(object1, object2 interface{}) bool {
	rfPstObject1 := reflect.ValueOf(object1)
	rfPstObject2 := reflect.ValueOf(object2)
	// 导出 object 的私有成员变量 obj（还是不太建议这样做，todo：优化）
	// 它返回一个reflect.Value表示指向指定值的指针field.Type()，unsafe.Pointer(field.UnsafeAddr())用作该指针。
	// 在此上下文reflect.NewAt中不同于reflect.New，后者将返回一个指向新初始化值的指针。
	//	备注： 下述操作相当于提取获取obj原始底层指针的reflect层指针的reflect层指针。
	rfObjectPtr1 := rfPstObject1.Elem().FieldByName("obj")
	rfObjectPtr2 := rfPstObject2.Elem().FieldByName("obj")
	rfObject1 := reflect.NewAt(rfObjectPtr1.Type(),
		unsafe.Pointer(rfObjectPtr1.UnsafeAddr())).Elem().Elem()
	rfObject2 := reflect.NewAt(rfObjectPtr2.Type(),
		unsafe.Pointer(rfObjectPtr2.UnsafeAddr())).Elem().Elem()

	rfMethod1 := rfObject1.MethodByName("TableName")
	results1 := rfMethod1.Call([]reflect.Value{})
	tblName1 := results1[0].Interface().(string)

	rfMethod2 := rfObject2.MethodByName("TableName")
	results2 := rfMethod2.Call([]reflect.Value{})
	tblName2 := results2[0].Interface().(string)
	curGoid := goroutine.GetID()
	if tblName1 != tblName2 {	// 对比是否访问同一张数据库表
		log.PST.Errorf("对象管理器CompareEntity()，object1与object2为不同记录，" +
			"数据表不一致：curGoid=%+v, tblName1=%+v, tblName2=%+v", curGoid, tblName1, tblName2)
		panic("tblName1 != tblName2")
		return false
	}
	rfObjTyp1 := rfObject1.Elem().Type()
	rfObjTyp2 := rfObject2.Elem().Type()
	if rfObjTyp1.NumField() != rfObjTyp2.NumField() { // 判断属性数量是否相等（有点多余，先保留）
		log.PST.Errorf("对象管理器CompareEntity()，object1与object2为不同记录，" +
			"属性数不一致：curGoid=%+v, obj1=%+v, obj2=%+v", curGoid, rfObject1.Elem().Interface(),
			rfObject2.Elem().Interface())
		panic("rfObjTyp1.NumField() != rfObjTyp2.NumField()")
		return false
	}
	rfID1 := rfObject1.Elem().FieldByName("ID")
	rfID2 := rfObject2.Elem().FieldByName("ID")
	if !rfID1.IsValid() {
		log.PST.Errorf("对象管理器CompareEntity(), object1属性ID不存在：" +
			"curGoid=%+v, obj1=%+v, obj2=%+v", curGoid, rfObject1.Elem().Interface(),
			rfObject2.Elem().Interface())
		panic("!rfID1.IsValid()")
	}
	if !rfID2.IsValid() {
		log.PST.Errorf("对象管理器CompareEntity(), object2属性ID不存在：" +
			"curGoid=%+v, obj1=%+v, obj2=%+v", curGoid, rfObject1.Elem().Interface(),
			rfObject2.Elem().Interface())
		panic("!rfID2.IsValid()")
	}
	if rfID1.Int() != rfID2.Int() { // 判断数据记录ID是否一致（这个条件可以确定是否同一条数据记录）
		log.PST.Infof("对象管理器CompareEntity()，object1与object2为不同记录，" +
			"属性值不一致：curGoid=%+v, fieldName=%+v, rfID1=%+v, rfID2=%+v",
			curGoid, "ID", rfID1.Int(), rfID2.Int())
		return false
	}
	// 上述所有条件判断都通过，则认为object1与object2是同一条DB数据
	log.PST.Infof("对象管理器CompareEntity()，object1与object2为同一记录：" +
		"curGoid=%+v, object1=%+v, object2=%+v, obj1=%+v, obj2=%+v", curGoid, object1,
		object2, rfObject1.Elem().Interface(), rfObject2.Elem().Interface())
	return true
}